package com.rpframework.core.mybatis;

import com.rpframework.core.mybatis.mapper.plugin.MapperScannerConfigurer;
import com.rpframework.core.mybatis.mapper.plugin.template.ResultMap;
import com.rpframework.utils.EntityUtils;
import com.rpframework.utils.StringUtil;
import org.apache.commons.lang3.StringUtils;

import javax.persistence.Id;
import javax.persistence.Transient;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 映射工具类
 * Created by jump on 2016/7/6.
 */
public class MapperUtils {
    /**
     * 字段之间分隔符
     */
    public static final String FIELD_SPLIT = ",";
    /**
     * 默认别名
     */
    public static final String[] ALIAS = new String[]{null, "Alias"};
    /**
     * 默认的别名
     */
    public static final String ALIAS_DEFAULT = ALIAS[0];

    public static final String ALIAS_SELECT = ALIAS[1];


    /**
     * 将java实体类转成数据库字段加别名
     * 支持继承
     *
     * @param alias 别名
     * @return select字段
     */
    public static String parseSqlSelect(String classAlias, String alias, String tableName) {
        Class<?> aClass = MapperScannerConfigurer.aliasChangeClass(classAlias);
        return parseSqlSelect(aClass, alias, tableName);
    }

    /**
     * 将java实体类转成数据库字段加别名
     * 支持继承
     *
     * @param alias 别名
     * @return select字段
     */
    public static String parseSqlSelect(String classAlias, String alias) {
        return parseSqlSelect(classAlias, alias, null);
    }

    /**
     * 将java实体类转成数据库字段加别名
     * 支持继承
     *
     * @return select字段
     */
    public static String parseSqlSelect(String classAlias) {
        return parseSqlSelect(classAlias, null);
    }


    /**
     * 将java实体类转成数据库字段加别名
     * 支持继承
     *
     * @param clazz 实体类
     * @return select字段
     */
    public static String parseSqlSelect(Class<?> clazz) {
        return parseSqlSelect(clazz, null);
    }

    /**
     * 将java实体类转成数据库字段加别名
     * 支持继承
     *
     * @param clazz 实体类
     * @return select字段
     */
    public static String parseSqlSelect(Class<?> clazz, String alias) {
        return parseSqlSelect(clazz, alias, null);
    }

    /**
     * 将java实体类转成数据库字段加别名
     * 支持继承
     *
     * @param clazz 实体类
     * @param alias 别名
     * @return select字段
     */
    public static String parseSqlSelect(Class<?> clazz, String alias, String tableName) {
        Class<?> superClass = clazz.getSuperclass();
        String select = "";
        if (!superClass.equals(Object.class)) {
            select = select + FIELD_SPLIT + genderAliasSelect(clazz, superClass.getDeclaredFields(), alias, tableName);
        }
        if (select.equals(FIELD_SPLIT)) {
            select = "";
        }
        Field[] declaredFields = clazz.getDeclaredFields();
        select = select + "," + genderAliasSelect(clazz, declaredFields, alias, tableName);
        if (StringUtil.isBlank(select)) {
            return null;
        }
        return select.substring(1);
    }

    public static String parseSqlSelectTable(Class<?> clazz, String tableName) {
        return parseSqlSelect(clazz, null, tableName);
    }

    public static String parseSqlSelectTable(String className, String tableName) {
        return parseSqlSelect(className, null, tableName);
    }


    public static String parseSqlSelectTableAlias(String className, String tableName) {
        return parseSqlSelect(className, ALIAS_SELECT.toLowerCase(), tableName);
    }

    public static String parseSqlSelectTableAlias(Class<?> clazz, String tableName) {
        return parseSqlSelectTableAlias(clazz.getSimpleName(), tableName);
    }

    public static String parseSqlSelectAlias(Class<?>... classes) {
        String[] classNames = new String[classes.length];
        for (int i = 0; i < classes.length; i++) {
            classNames[i] = classes[i].getSimpleName();
        }
        return parseSqlSelectAlias(classNames);
    }

    public static String parseSqlSelectAlias(String... classNames) {
        String select = "";
        for (String className :
                classNames) {
            select += FIELD_SPLIT + parseSqlSelectTableAlias(className, null);

        }
        return select.substring(1);
    }

    public static String selectAlias(String classNames) {
        String[] split = classNames.split(FIELD_SPLIT);
        return parseSqlSelectAlias(split);
    }


    /**
     * 类转结果集
     *
     * @param clazz 类
     * @return 结果集
     */
    public static ResultMap parseResultMap(Class<?> clazz, String alias) {
        Class<?> superclass = clazz.getSuperclass();
        ResultMap resultMap = null;
        if (superclass != null) {
            if (!Object.class.equals(superclass)) {
                Field[] declaredFields = superclass.getDeclaredFields();
                resultMap = parseResultMap(clazz, declaredFields, alias);
            }
        }
        Field[] declaredFields = clazz.getDeclaredFields();
        ResultMap resultMap2 = parseResultMap(clazz, declaredFields, alias);

        if (resultMap == null) {
            resultMap = resultMap2;
        } else {
            ResultMap.Id idResult = resultMap2.getIdResult();
            if (idResult != null) {
                resultMap.setIdResult(idResult);
            }
            if (resultMap2.getResult().getMaps().size() > 0) {
                Set<ResultMap.Map> maps = resultMap2.getResult().getMaps();
                for (ResultMap.Map map :
                        maps) {
                    resultMap.getResult().getMaps().add(map);
                }
            }
        }
        String simpleName = clazz.getSimpleName();
        if (alias == null) {
            alias = "";
        }
        alias += "RM";
        resultMap.setId(alias);
        resultMap.setType(simpleName);
        return resultMap;
    }

    /**
     * 类转结果集
     *
     * @param clazz 类
     * @return 结果集
     */
    public static ResultMap parseResultMap(Class<?> clazz) {
        return parseResultMap(clazz, ALIAS_DEFAULT);
    }

    /**
     * 类转结果集
     *
     * @param clazz 类
     * @return 结果集
     */
    public static List<ResultMap> parseResultMaps(Class<?> clazz) {
        List<ResultMap> resultMaps = new ArrayList<>();
        for (String one :
                getAlias()) {
            resultMaps.add(parseResultMap(clazz, one));
        }
        return resultMaps;
    }


    public static ResultMap parseResultMap(Class<?> clazz, Field[] declaredFields, String alias) {
        return parseResultMap(clazz.getSimpleName(), declaredFields, alias);
    }

    /**
     * 字段转结果集
     *
     * @param declaredFields 字段
     * @return 结果集
     */
    public static ResultMap parseResultMap(String className, Field[] declaredFields, String alias) {
        ResultMap resultMap = new ResultMap();
        resultMap.setResult(new ResultMap().new Result());
        Set<ResultMap.Map> maps = new HashSet<>();
        resultMap.getResult().setMaps(maps);

        if (declaredFields != null) {
            for (Field field :
                    declaredFields) {
                if (field.getAnnotation(Transient.class) == null) {
                    ResultMap.Map map = parseResultMapMap(className, field, alias);
                    if (field.getAnnotation(Id.class) != null) {
                        ResultMap.Id id = new ResultMap().new Id();
                        id.setMap(map);
                        resultMap.setIdResult(id);
                    } else {
                        resultMap.getResult().getMaps().add(map);
                    }
                }
            }
        }
        return resultMap;
    }

    /**
     * 字段转换结果集
     *
     * @param field 字段
     * @return 结果集
     */
    public static ResultMap.Map parseResultMapMap(String className, Field field, String alias) {
        return new ResultMap().new Map(genderAlias(className, field.getName(), alias).toLowerCase(), field.getName());
    }

    /**
     * @param field 字段
     * @param alias 别名
     * @return 字段+别名
     */
    public static String genderAlias(Class<?> clazz, String field, String alias) {
        return genderAlias(clazz.getSimpleName(), field, alias);
    }

    /**
     * @param field 字段
     * @return 字段+别名
     */
    public static String genderAlias(Class<?> clazz, String field) {
        return genderAlias(clazz, field, null);
    }

    /**
     * 生产查询语句的别名
     *
     * @param className 类名
     * @param field     字段名
     * @param alias     别名
     * @param tableName 表名 if??=类名
     * @return 别名
     */
    public static String genderAliasSelect(String className, String field, String alias, String tableName) {
        if (StringUtils.isBlank(tableName)) {
            tableName = className;
        }
        return EntityUtils.javaToNamingHump(tableName) + "." + EntityUtils.javaToNamingHump(field) + " AS " +
                genderAlias(className, field, alias);
    }


    public static String genderAliasSelect(Class<?> clazz, String field, String alias, String tableName) {
        return genderAliasSelect(clazz.getSimpleName(), field, alias, tableName);
    }

    /**
     * 没有别名
     *
     * @param clazz     类
     * @param field     字段
     * @param tableName 表名
     * @return 查询
     */
    public static String genderAliasSelect(Class<?> clazz, String field, String tableName) {
        return genderAliasSelect(clazz, field, null, tableName);
    }

    /**
     * 生产查询语句的别名
     *
     * @param className 类名
     * @param field     字段名
     * @param alias     别名
     * @return 别名
     */
    public static String genderAliasSelect(String className, String field, String alias) {
        return genderAliasSelect(className, field, alias, null);
    }

    /**
     * 生产查询语句的别名
     *
     * @param className 类名
     * @param fields    字段名
     * @param alias     别名
     * @param tableName 表名 if??=类名
     * @return 别名
     */
    public static String genderAliasSelect(String className, String[] fields, String alias, String tableName) {
        if (fields == null || fields.length < 0) {
            throw new RuntimeException("字段至少有一个");
        }
        String select = "";
        for (String field :
                fields) {
            select += ", " + genderAliasSelect(className, field, alias, tableName);
        }
        return select.substring(1);
    }

    /**
     * 生产查询语句的别名
     *
     * @param className 类名
     * @param fields    字段名
     * @param alias     别名
     * @return 别名
     */
    public static String genderAliasSelect(String className, String[] fields, String alias) {
        return genderAliasSelect(className, fields, alias, null);
    }

    public static String genderAliasSelect(Class<?> clazz, Field[] fields, String alias, String tableName) {
        return genderAliasSelect(clazz.getSimpleName(), fields, alias, tableName);
    }

    public static String genderAliasSelect(String className, Field[] fields, String alias, String tableName) {
        List<String> listString = new ArrayList<>();

        for (Field field :
                fields) {
            if (field.getAnnotation(Transient.class) == null) {
                listString.add(field.getName());
            }
        }

        String[] fieldsString = new String[listString.size()];
        listString.toArray(fieldsString);

        return genderAliasSelect(className, fieldsString, alias, tableName);
    }

    public static String genderAliasSelect(String className, Field[] fields, String alias) {
        return genderAliasSelect(className, fields, alias, null);
    }


    /**
     * @param field 字段
     * @param alias 别名
     * @return 字段+别名
     */
    public static String genderAlias(String className, String field, String alias) {
        if (StringUtils.isBlank(field)) {
            throw new RuntimeException("字段名是空字符串");
        }
        if (StringUtils.isBlank(alias)) {
            return EntityUtils.javaToNamingHump(field);
        }
        field = genderAliasClass(className, field);
        if (!StringUtil.isBlank(alias)) {
            field = alias + "_" + field;
        }
        return field;
    }

    /**
     * 生成别名
     *
     * @param className 类名
     * @param field     字段名
     * @return 别名
     */
    public static String genderAliasClass(String className, String field) {
        if (StringUtils.isBlank(className)) {
            return EntityUtils.javaToNamingHump(field);
        }
        return EntityUtils.javaToNamingHump(className) + "_" + EntityUtils.javaToNamingHump(field);
    }

    /**
     * 生成别名
     *
     * @param field 字段
     * @return 字段+别名
     */
    public static String genderAlias(String className, String field) {
        return genderAlias(className, field, null);
    }

    /**
     * 获取所有别名
     *
     * @return 别名
     */
    public static String[] getAlias() {
        return ALIAS;
    }
}
